home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 16 / AMIGAplus Sonderheft 16 (1998)(ICP)(DE)[!].iso / pd / anwendungen / ispell-3.1.18src / tgood.c < prev    next >
C/C++ Source or Header  |  1994-11-02  |  21KB  |  662 lines

  1. #ifndef lint
  2. static char Rcs_Id[] =
  3.     "$Id: tgood.c,v 1.32 1994/11/02 06:56:16 geoff Exp $";
  4. #endif
  5.  
  6. /*
  7.  * Copyright 1987, 1988, 1989, 1992, 1993, Geoff Kuenning, Granada Hills, CA
  8.  * All rights reserved.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  *
  14.  * 1. Redistributions of source code must retain the above copyright
  15.  *    notice, this list of conditions and the following disclaimer.
  16.  * 2. Redistributions in binary form must reproduce the above copyright
  17.  *    notice, this list of conditions and the following disclaimer in the
  18.  *    documentation and/or other materials provided with the distribution.
  19.  * 3. All modifications to the source code must be clearly marked as
  20.  *    such.  Binary redistributions based on modified source code
  21.  *    must be clearly marked as modified versions in the documentation
  22.  *    and/or other materials provided with the distribution.
  23.  * 4. All advertising materials mentioning features or use of this software
  24.  *    must display the following acknowledgment:
  25.  *      This product includes software developed by Geoff Kuenning and
  26.  *      other unpaid contributors.
  27.  * 5. The name of Geoff Kuenning may not be used to endorse or promote
  28.  *    products derived from this software without specific prior
  29.  *    written permission.
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
  32.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34.  * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
  35.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  39.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  40.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  41.  * SUCH DAMAGE.
  42.  */
  43.  
  44. /*
  45.  * Table-driven version of good.c.
  46.  *
  47.  * Geoff Kuenning, July 1987
  48.  */
  49.  
  50. /*
  51.  * $Log: tgood.c,v $
  52.  * Revision 1.32  1994/11/02  06:56:16  geoff
  53.  * Remove the anyword feature, which I've decided is a bad idea.
  54.  *
  55.  * Revision 1.31  1994/10/25  05:46:25  geoff
  56.  * Add support for the FF_ANYWORD (affix applies to all words, even if
  57.  * flag bit isn't set) flag option.
  58.  *
  59.  * Revision 1.30  1994/05/24  06:23:08  geoff
  60.  * Don't create a hit if "allhits" is clear and capitalization
  61.  * mismatches.  This cures a bug where a word could be in the dictionary
  62.  * and yet not found.
  63.  *
  64.  * Revision 1.29  1994/05/17  06:44:21  geoff
  65.  * Add support for controlled compound formation and the COMPOUNDONLY
  66.  * option to affix flags.
  67.  *
  68.  * Revision 1.28  1994/01/25  07:12:13  geoff
  69.  * Get rid of all old RCS log lines in preparation for the 3.1 release.
  70.  *
  71.  */
  72.  
  73. #include <ctype.h>
  74. #include "config.h"
  75. #include "ispell.h"
  76. #include "proto.h"
  77.  
  78. void        chk_aff P ((ichar_t * word, ichar_t * ucword, int len,
  79.           int ignoreflagbits, int allhits, int pfxopts, int sfxopts));
  80. static void    pfx_list_chk P ((ichar_t * word, ichar_t * ucword,
  81.           int len, int optflags, int sfxopts, struct flagptr * ind,
  82.           int ignoreflagbits, int allhits));
  83. static void    chk_suf P ((ichar_t * word, ichar_t * ucword, int len,
  84.           int optflags, struct flagent * pfxent, int ignoreflagbits,
  85.           int allhits));
  86. static void    suf_list_chk P ((ichar_t * word, ichar_t * ucword, int len,
  87.           struct flagptr * ind, int optflags, struct flagent * pfxent,
  88.           int ignoreflagbits, int allhits));
  89. int        expand_pre P ((char * croot, ichar_t * rootword,
  90.           MASKTYPE mask[], int option, char * extra));
  91. static int    pr_pre_expansion P ((char * croot, ichar_t * rootword,
  92.           struct flagent * flent, MASKTYPE mask[], int option,
  93.           char * extra));
  94. int        expand_suf P ((char * croot, ichar_t * rootword,
  95.           MASKTYPE mask[], int optflags, int option, char * extra));
  96. static int    pr_suf_expansion P ((char * croot, ichar_t * rootword,
  97.           struct flagent * flent, int option, char * extra));
  98. static void    forcelc P ((ichar_t * dst, int len));
  99.  
  100. /* Check possible affixes */
  101. void chk_aff (word, ucword, len, ignoreflagbits, allhits, pfxopts, sfxopts)
  102.     ichar_t *        word;        /* Word to be checked */
  103.     ichar_t *        ucword;        /* Upper-case-only copy of word */
  104.     int            len;        /* The length of word/ucword */
  105.     int            ignoreflagbits;    /* Ignore whether affix is legal */
  106.     int            allhits;    /* Keep going after first hit */
  107.     int            pfxopts;    /* Options to apply to prefixes */
  108.     int            sfxopts;    /* Options to apply to suffixes */
  109.     {
  110.     register ichar_t *    cp;        /* Pointer to char to index on */
  111.     struct flagptr *    ind;        /* Flag index table to test */
  112.  
  113.     pfx_list_chk (word, ucword, len, pfxopts, sfxopts, &pflagindex[0],
  114.       ignoreflagbits, allhits);
  115.     cp = ucword;
  116.     ind = &pflagindex[*cp++];
  117.     while (ind->numents == 0  &&  ind->pu.fp != NULL)
  118.     {
  119.     if (*cp == 0)
  120.         return;
  121.     if (ind->pu.fp[0].numents)
  122.         {
  123.         pfx_list_chk (word, ucword, len, pfxopts, sfxopts, &ind->pu.fp[0],
  124.           ignoreflagbits, allhits);
  125.         if (numhits  &&  !allhits  &&  !cflag  &&  !ignoreflagbits)
  126.         return;
  127.         }
  128.     ind = &ind->pu.fp[*cp++];
  129.     }
  130.     pfx_list_chk (word, ucword, len, pfxopts, sfxopts, ind, ignoreflagbits,
  131.       allhits);
  132.     if (numhits  &&  !allhits  &&  !cflag  &&  !ignoreflagbits)
  133.     return;
  134.     chk_suf (word, ucword, len, sfxopts, (struct flagent *) NULL,
  135.       ignoreflagbits, allhits);
  136.     }
  137.  
  138. /* Check some prefix flags */
  139. static void pfx_list_chk (word, ucword, len, optflags, sfxopts, ind,
  140.   ignoreflagbits, allhits)
  141.     ichar_t *        word;        /* Word to be checked */
  142.     ichar_t *        ucword;        /* Upper-case-only word */
  143.     int            len;        /* The length of ucword */
  144.     int            optflags;    /* Options to apply */
  145.     int            sfxopts;    /* Options to apply to suffixes */
  146.     struct flagptr *    ind;        /* Flag index table */
  147.     int            ignoreflagbits;    /* Ignore whether affix is legal */
  148.     int            allhits;    /* Keep going after first hit */
  149.     {
  150.     int            cond;        /* Condition number */
  151.     register ichar_t *    cp;        /* Pointer into end of ucword */
  152.     struct dent *    dent;        /* Dictionary entry we found */
  153.     int            entcount;    /* Number of entries to process */
  154.     register struct flagent *
  155.             flent;        /* Current table entry */
  156.     int            preadd;        /* Length added to tword2 as prefix */
  157.     register int    tlen;        /* Length of tword */
  158.     ichar_t        tword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4]; /* Tmp cpy */
  159.     ichar_t        tword2[sizeof tword]; /* 2nd copy for ins_root_cap */
  160.  
  161.     for (flent = ind->pu.ent, entcount = ind->numents;
  162.       entcount > 0;
  163.       flent++, entcount--)
  164.     {
  165.     /*
  166.      * If this is a compound-only affix, ignore it unless we're
  167.      * looking for that specific thing.
  168.      */
  169.     if ((flent->flagflags & FF_COMPOUNDONLY) != 0
  170.       &&  (optflags & FF_COMPOUNDONLY) == 0)
  171.         continue;
  172.     /*
  173.      * In COMPOUND_CONTROLLED mode, the FF_COMPOUNDONLY bit must
  174.      * match exactly.
  175.      */
  176.     if (compoundflag == COMPOUND_CONTROLLED
  177.       &&  ((flent->flagflags ^ optflags) & FF_COMPOUNDONLY) != 0)
  178.         continue;
  179.     /*
  180.      * See if the prefix matches.
  181.      */
  182.     tlen = len - flent->affl;
  183.     if (tlen > 0
  184.       &&  (flent->affl == 0
  185.         ||  icharncmp (flent->affix, ucword, flent->affl) == 0)
  186.       &&  tlen + flent->stripl >= flent->numconds)
  187.         {
  188.         /*
  189.          * The prefix matches.  Remove it, replace it by the "strip"
  190.          * string (if any), and check the original conditions.
  191.          */
  192.         if (flent->stripl)
  193.         (void) icharcpy (tword, flent->strip);
  194.         (void) icharcpy (tword + flent->stripl, ucword + flent->affl);
  195.         cp = tword;
  196.         for (cond = 0;  cond < flent->numconds;  cond++)
  197.         {
  198.         if ((flent->conds[*cp++] & (1 << cond)) == 0)
  199.             break;
  200.         }
  201.         if (cond >= flent->numconds)
  202.         {
  203.         /*
  204.          * The conditions match.  See if the word is in the
  205.          * dictionary.
  206.          */
  207.         tlen += flent->stripl;
  208.         if (cflag)
  209.             flagpr (tword, BITTOCHAR (flent->flagbit), flent->stripl,
  210.               flent->affl, -1, 0);
  211.         else if (ignoreflagbits)
  212.             {
  213.             if ((dent = lookup (tword, 1)) != NULL)
  214.             {
  215.             cp = tword2;
  216.             if (flent->affl)
  217.                 {
  218.                 (void) icharcpy (cp, flent->affix);
  219.                 cp += flent->affl;
  220.                 *cp++ = '+';
  221.                 }
  222.             preadd = cp - tword2;
  223.             (void) icharcpy (cp, tword);
  224.             cp += tlen;
  225.             if (flent->stripl)
  226.                 {
  227.                 *cp++ = '-';
  228.                 (void) icharcpy (cp, flent->strip);
  229.                 }
  230.             (void) ins_root_cap (tword2, word,
  231.               flent->stripl, preadd,
  232.               0, (cp - tword2) - tlen - preadd,
  233.               dent, flent, (struct flagent *) NULL);
  234.             }
  235.             }
  236.         else if ((dent = lookup (tword, 1)) != NULL
  237.           &&  TSTMASKBIT (dent->mask, flent->flagbit))
  238.             {
  239.             if (numhits < MAX_HITS)
  240.             {
  241.             hits[numhits].dictent = dent;
  242.             hits[numhits].prefix = flent;
  243.             hits[numhits].suffix = NULL;
  244.             numhits++;
  245.             }
  246.             if (!allhits)
  247.             {
  248. #ifndef NO_CAPITALIZATION_SUPPORT
  249.             if (cap_ok (word, &hits[0], len))
  250.                 return;
  251.             numhits = 0;
  252. #else /* NO_CAPITALIZATION_SUPPORT */
  253.             return;
  254. #endif /* NO_CAPITALIZATION_SUPPORT */
  255.             }
  256.             }
  257.         /*
  258.          * Handle cross-products.
  259.          */
  260.         if (flent->flagflags & FF_CROSSPRODUCT)
  261.             chk_suf (word, tword, tlen, sfxopts | FF_CROSSPRODUCT,
  262.               flent, ignoreflagbits, allhits);
  263.         }
  264.         }
  265.     }
  266.     }
  267.  
  268. /* Check possible suffixes */
  269. static void chk_suf (word, ucword, len, optflags, pfxent, ignoreflagbits,
  270.   allhits)
  271.     ichar_t *        word;        /* Word to be checked */
  272.     ichar_t *        ucword;        /* Upper-case-only word */
  273.     int            len;        /* The length of ucword */
  274.     int            optflags;    /* Affix option flags */
  275.     struct flagent *    pfxent;        /* Prefix flag entry if cross-prod */
  276.     int            ignoreflagbits;    /* Ignore whether affix is legal */
  277.     int            allhits;    /* Keep going after first hit */
  278.     {
  279.     register ichar_t *    cp;        /* Pointer to char to index on */
  280.     struct flagptr *    ind;        /* Flag index table to test */
  281.  
  282.     suf_list_chk (word, ucword, len, &sflagindex[0], optflags, pfxent,
  283.       ignoreflagbits, allhits);
  284.     cp = ucword + len - 1;
  285.     ind = &sflagindex[*cp];
  286.     while (ind->numents == 0  &&  ind->pu.fp != NULL)
  287.     {
  288.     if (cp == ucword)
  289.         return;
  290.     if (ind->pu.fp[0].numents)
  291.         {
  292.         suf_list_chk (word, ucword, len, &ind->pu.fp[0],
  293.           optflags, pfxent, ignoreflagbits, allhits);
  294.         if (numhits != 0  &&  !allhits  &&  !cflag  &&  !ignoreflagbits)
  295.         return;
  296.         }
  297.     ind = &ind->pu.fp[*--cp];
  298.     }
  299.     suf_list_chk (word, ucword, len, ind, optflags, pfxent,
  300.       ignoreflagbits, allhits);
  301.     }
  302.     
  303. static void suf_list_chk (word, ucword, len, ind, optflags, pfxent,
  304.   ignoreflagbits, allhits)
  305.     ichar_t *        word;        /* Word to be checked */
  306.     ichar_t *        ucword;        /* Upper-case-only word */
  307.     int            len;        /* The length of ucword */
  308.     struct flagptr *    ind;        /* Flag index table */
  309.     int            optflags;    /* Affix option flags */
  310.     struct flagent *    pfxent;        /* Prefix flag entry if crossonly */
  311.     int            ignoreflagbits;    /* Ignore whether affix is legal */
  312.     int            allhits;    /* Keep going after first hit */
  313.     {
  314.     register ichar_t *    cp;        /* Pointer into end of ucword */
  315.     int            cond;        /* Condition number */
  316.     struct dent *    dent;        /* Dictionary entry we found */
  317.     int            entcount;    /* Number of entries to process */
  318.     register struct flagent *
  319.             flent;        /* Current table entry */
  320.     int            preadd;        /* Length added to tword2 as prefix */
  321.     register int    tlen;        /* Length of tword */
  322.     ichar_t        tword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4]; /* Tmp cpy */
  323.     ichar_t        tword2[sizeof tword]; /* 2nd copy for ins_root_cap */
  324.  
  325.     (void) icharcpy (tword, ucword);
  326.     for (flent = ind->pu.ent, entcount = ind->numents;
  327.       entcount > 0;
  328.       flent++, entcount--)
  329.     {
  330.     if ((optflags & FF_CROSSPRODUCT) != 0
  331.       &&  (flent->flagflags & FF_CROSSPRODUCT) == 0)
  332.         continue;
  333.     /*
  334.      * If this is a compound-only affix, ignore it unless we're
  335.      * looking for that specific thing.
  336.      */
  337.     if ((flent->flagflags & FF_COMPOUNDONLY) != 0
  338.       &&  (optflags & FF_COMPOUNDONLY) == 0)
  339.         continue;
  340.     /*
  341.      * In COMPOUND_CONTROLLED mode, the FF_COMPOUNDONLY bit must
  342.      * match exactly.
  343.      */
  344.     if (compoundflag == COMPOUND_CONTROLLED
  345.       &&  ((flent->flagflags ^ optflags) & FF_COMPOUNDONLY) != 0)
  346.         continue;
  347.     /*
  348.      * See if the suffix matches.
  349.      */
  350.     tlen = len - flent->affl;
  351.     if (tlen > 0
  352.       &&  (flent->affl == 0
  353.         ||  icharcmp (flent->affix, ucword + tlen) == 0)
  354.       &&  tlen + flent->stripl >= flent->numconds)
  355.         {
  356.         /*
  357.          * The suffix matches.  Remove it, replace it by the "strip"
  358.          * string (if any), and check the original conditions.
  359.          */
  360.         (void) icharcpy (tword, ucword);
  361.         cp = tword + tlen;
  362.         if (flent->stripl)
  363.         {
  364.         (void) icharcpy (cp, flent->strip);
  365.         tlen += flent->stripl;
  366.         cp = tword + tlen;
  367.         }
  368.         else
  369.         *cp = '\0';
  370.         for (cond = flent->numconds;  --cond >= 0;  )
  371.         {
  372.         if ((flent->conds[*--cp] & (1 << cond)) == 0)
  373.             break;
  374.         }
  375.         if (cond < 0)
  376.         {
  377.         /*
  378.          * The conditions match.  See if the word is in the
  379.          * dictionary.
  380.          */
  381.         if (cflag)
  382.             {
  383.             if (optflags & FF_CROSSPRODUCT)
  384.             flagpr (tword, BITTOCHAR (pfxent->flagbit),
  385.               pfxent->stripl, pfxent->affl,
  386.               BITTOCHAR (flent->flagbit), flent->affl);
  387.             else
  388.             flagpr (tword, -1, 0, 0,
  389.               BITTOCHAR (flent->flagbit), flent->affl);
  390.             }
  391.         else if (ignoreflagbits)
  392.             {
  393.             if ((dent = lookup (tword, 1)) != NULL)
  394.             {
  395.             cp = tword2;
  396.             if ((optflags & FF_CROSSPRODUCT)
  397.               &&  pfxent->affl != 0)
  398.                 {
  399.                 (void) icharcpy (cp, pfxent->affix);
  400.                 cp += pfxent->affl;
  401.                 *cp++ = '+';
  402.                 }
  403.             preadd = cp - tword2;
  404.             (void) icharcpy (cp, tword);
  405.             cp += tlen;
  406.             if ((optflags & FF_CROSSPRODUCT)
  407.               &&  pfxent->stripl != 0)
  408.                 {
  409.                 *cp++ = '-';
  410.                 (void) icharcpy (cp, pfxent->strip);
  411.                 cp += pfxent->stripl;
  412.                 }
  413.             if (flent->stripl)
  414.                 {
  415.                 *cp++ = '-';
  416.                 (void) icharcpy (cp, flent->strip);
  417.                 cp += flent->stripl;
  418.                 }
  419.             if (flent->affl)
  420.                 {
  421.                 *cp++ = '+';
  422.                 (void) icharcpy (cp, flent->affix);
  423.                 cp += flent->affl;
  424.                 }
  425.             (void) ins_root_cap (tword2, word,
  426.               (optflags & FF_CROSSPRODUCT) ? pfxent->stripl : 0,
  427.               preadd,
  428.               flent->stripl, (cp - tword2) - tlen - preadd,
  429.               dent, pfxent, flent);
  430.             }
  431.             }
  432.         else if ((dent = lookup (tword, 1)) != NULL
  433.           &&  TSTMASKBIT (dent->mask, flent->flagbit)
  434.           &&  ((optflags & FF_CROSSPRODUCT) == 0
  435.             || TSTMASKBIT (dent->mask, pfxent->flagbit)))
  436.             {
  437.             if (numhits < MAX_HITS)
  438.             {
  439.             hits[numhits].dictent = dent;
  440.             hits[numhits].prefix = pfxent;
  441.             hits[numhits].suffix = flent;
  442.             numhits++;
  443.             }
  444.             if (!allhits)
  445.             {
  446. #ifndef NO_CAPITALIZATION_SUPPORT
  447.             if (cap_ok (word, &hits[0], len))
  448.                 return;
  449.             numhits = 0;
  450. #else /* NO_CAPITALIZATION_SUPPORT */
  451.             return;
  452. #endif /* NO_CAPITALIZATION_SUPPORT */
  453.             }
  454.             }
  455.         }
  456.         }
  457.     }
  458.     }
  459.  
  460. /*
  461.  * Expand a dictionary prefix entry
  462.  */
  463. int expand_pre (croot, rootword, mask, option, extra)
  464.     char *            croot;        /* Char version of rootword */
  465.     ichar_t *            rootword;    /* Root word to expand */
  466.     register MASKTYPE        mask[];        /* Mask bits to expand on */
  467.     int                option;        /* Option, see expandmode */
  468.     char *            extra;        /* Extra info to add to line */
  469.     {
  470.     int                entcount;    /* No. of entries to process */
  471.     int                explength;    /* Length of expansions */
  472.     register struct flagent *
  473.                 flent;        /* Current table entry */
  474.  
  475.     for (flent = pflaglist, entcount = numpflags, explength = 0;
  476.       entcount > 0;
  477.       flent++, entcount--)
  478.     {
  479.     if (TSTMASKBIT (mask, flent->flagbit))
  480.         explength +=
  481.           pr_pre_expansion (croot, rootword, flent, mask, option, extra);
  482.     }
  483.     return explength;
  484.     }
  485.  
  486. /* Print a prefix expansion */
  487. static int pr_pre_expansion (croot, rootword, flent, mask, option, extra)
  488.     char *            croot;        /* Char version of rootword */
  489.     register ichar_t *        rootword;    /* Root word to expand */
  490.     register struct flagent *    flent;        /* Current table entry */
  491.     MASKTYPE            mask[];        /* Mask bits to expand on */
  492.     int                option;        /* Option, see    expandmode */
  493.     char *            extra;        /* Extra info to add to line */
  494.     {
  495.     int                cond;        /* Current condition number */
  496.     register ichar_t *        nextc;        /* Next case choice */
  497.     int                tlen;        /* Length of tword */
  498.     ichar_t            tword[INPUTWORDLEN + MAXAFFIXLEN]; /* Temp */
  499.  
  500.     tlen = icharlen (rootword);
  501.     if (flent->numconds > tlen)
  502.     return 0;
  503.     tlen -= flent->stripl;
  504.     if (tlen <= 0)
  505.     return 0;
  506.     tlen += flent->affl;
  507.     for (cond = 0, nextc = rootword;  cond < flent->numconds;  cond++)
  508.     {
  509.     if ((flent->conds[mytoupper (*nextc++)] & (1 << cond)) == 0)
  510.         return 0;
  511.     }
  512.     /*
  513.      * The conditions are satisfied.  Copy the word, add the prefix,
  514.      * and make it the proper case.   This code is carefully written
  515.      * to match that ins_cap and cap_ok.  Note that the affix, as
  516.      * inserted, is uppercase.
  517.      *
  518.      * There is a tricky bit here:  if the root is capitalized, we
  519.      * want a capitalized result.  If the root is followcase, however,
  520.      * we want to duplicate the case of the first remaining letter
  521.      * of the root.  In other words, "Loved/U" should generate "Unloved",
  522.      * but "LOved/U" should generate "UNLOved" and "lOved/U" should
  523.      * produce "unlOved".
  524.      */
  525.     if (flent->affl)
  526.     {
  527.     (void) icharcpy (tword, flent->affix);
  528.     nextc = tword + flent->affl;
  529.     }
  530.     (void) icharcpy (nextc, rootword + flent->stripl);
  531.     if (myupper (rootword[0]))
  532.     {
  533.     /* We must distinguish followcase from capitalized and all-upper */
  534.     for (nextc = rootword + 1;  *nextc;  nextc++)
  535.         {
  536.         if (!myupper (*nextc))
  537.         break;
  538.         }
  539.     if (*nextc)
  540.         {
  541.         /* It's a followcase or capitalized word.  Figure out which. */
  542.         for (  ;  *nextc;  nextc++)
  543.         {
  544.         if (myupper (*nextc))
  545.             break;
  546.         }
  547.         if (*nextc)
  548.         {
  549.         /* It's followcase. */
  550.         if (!myupper (tword[flent->affl]))
  551.             forcelc (tword, flent->affl);
  552.         }
  553.         else
  554.         {
  555.         /* It's capitalized */
  556.         forcelc (tword + 1, tlen - 1);
  557.         }
  558.         }
  559.     }
  560.     else
  561.     {
  562.     /* Followcase or all-lower, we don't care which */
  563.     if (!myupper (*nextc))
  564.         forcelc (tword, flent->affl);
  565.     }
  566.     if (option == 3)
  567.     (void) printf ("\n%s", croot);
  568.     if (option != 4)
  569.     (void) printf (" %s%s", ichartosstr (tword, 1), extra);
  570.     if (flent->flagflags & FF_CROSSPRODUCT)
  571.     return tlen
  572.       + expand_suf (croot, tword, mask, FF_CROSSPRODUCT, option, extra);
  573.     else
  574.     return tlen;
  575.     }
  576.  
  577. /*
  578.  * Expand a dictionary suffix entry
  579.  */
  580. int expand_suf (croot, rootword, mask, optflags, option, extra)
  581.     char *            croot;        /* Char version of rootword */
  582.     ichar_t *            rootword;    /* Root word to expand */
  583.     register MASKTYPE        mask[];        /* Mask bits to expand on */
  584.     int                optflags;    /* Affix option flags */
  585.     int                option;        /* Option, see expandmode */
  586.     char *            extra;        /* Extra info to add to line */
  587.     {
  588.     int                entcount;    /* No. of entries to process */
  589.     int                explength;    /* Length of expansions */
  590.     register struct flagent *
  591.                 flent;        /* Current table entry */
  592.  
  593.     for (flent = sflaglist, entcount = numsflags, explength = 0;
  594.       entcount > 0;
  595.       flent++, entcount--)
  596.     {
  597.     if (TSTMASKBIT (mask, flent->flagbit))
  598.         {
  599.         if ((optflags & FF_CROSSPRODUCT) == 0
  600.           ||  (flent->flagflags & FF_CROSSPRODUCT))
  601.         explength +=
  602.           pr_suf_expansion (croot, rootword, flent, option, extra);
  603.         }
  604.     }
  605.     return explength;
  606.     }
  607.  
  608. /* Print a suffix expansion */
  609. static int pr_suf_expansion (croot, rootword, flent, option, extra)
  610.     char *            croot;        /* Char version of rootword */
  611.     register ichar_t *        rootword;    /* Root word to expand */
  612.     register struct flagent *    flent;        /* Current table entry */
  613.     int                option;        /* Option, see expandmode */
  614.     char *            extra;        /* Extra info to add to line */
  615.     {
  616.     int                cond;        /* Current condition number */
  617.     register ichar_t *        nextc;        /* Next case choice */
  618.     int                tlen;        /* Length of tword */
  619.     ichar_t            tword[INPUTWORDLEN + MAXAFFIXLEN]; /* Temp */
  620.  
  621.     tlen = icharlen (rootword);
  622.     cond = flent->numconds;
  623.     if (cond > tlen)
  624.     return 0;
  625.     if (tlen - flent->stripl <= 0)
  626.     return 0;
  627.     for (nextc = rootword + tlen;  --cond >= 0;  )
  628.     {
  629.     if ((flent->conds[mytoupper (*--nextc)] & (1 << cond)) == 0)
  630.         return 0;
  631.     }
  632.     /*
  633.      * The conditions are satisfied.  Copy the word, add the suffix,
  634.      * and make it match the case of the last remaining character of the
  635.      * root.  Again, this code carefully matches ins_cap and cap_ok.
  636.      */
  637.     (void) icharcpy (tword, rootword);
  638.     nextc = tword + tlen - flent->stripl;
  639.     if (flent->affl)
  640.     {
  641.     (void) icharcpy (nextc, flent->affix);
  642.     if (!myupper (nextc[-1]))
  643.         forcelc (nextc, flent->affl);
  644.     }
  645.     else
  646.     *nextc = 0;
  647.     if (option == 3)
  648.     (void) printf ("\n%s", croot);
  649.     if (option != 4)
  650.     (void) printf (" %s%s", ichartosstr (tword, 1), extra);
  651.     return tlen + flent->affl - flent->stripl;
  652.     }
  653.  
  654. static void forcelc (dst, len)            /* Force to lowercase */
  655.     register ichar_t *        dst;        /* Destination to modify */
  656.     register int        len;        /* Length to copy */
  657.     {
  658.  
  659.     for (  ;  --len >= 0;  dst++)
  660.     *dst = mytolower (*dst);
  661.     }
  662.